function f_exe_osc_comm()
{   #执行osc命令的函数
    declare fun_name md5_sql
    fun_name="f_exe_osc_comm"
    _tools="${1}"
    F_str="$(awk '{print $1" "$2" "$3}' <<< "${line}")"
    sql="$(awk -F"${F_str}" '{print $2}' <<< "${line}"|sed 's/`/\\`/g;s/"/\\"/g')"

    f_check_diy_info "${_tools}" "${first_order}" || true             #检查用户diy配置, 对应dbadb_alter_table_repl_time表

    #f_check_table_and_disk_size "${_t_}" || return 0 #检查磁盘空间及表大小是否符合预设判断逻辑, 如果不符合就返回

    if [ "${_tools}x" == "gh-ostx" ]
    then
        #如果是ghost就多新建一个表, 避免ghost执行失败污染测试环境, 因为ghost失败后可能会使用pt重新跑
        #f_exe_sql_in_test_mysql "create table ${test_db}.${t_tmp}_ghost like ${test_db}.${t_tmp};" >> ${log_file}  
        f_init_ghost_opt
        osc_comm="timeout 60s gh-ost --host=${test_host} --port=${test_port} --user=${test_user} --password=${test_pass} --database=${test_db}"
        osc_comm="${osc_comm} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        osc_comm_tmp="gh-ost --host=${test_host} --port=${test_port} --user=${test_user} --password=xxxxxx --database=${test_db}"
        osc_comm_tmp="${osc_comm_tmp} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        [ "${slave_mark_sbm}x" != "604800x" ] && osc_array+=("--throttle-control-replicas=${check_slave_repl_list}")  #如果是生产就判断延迟
    else
        f_init_ptosc_opt
        osc_comm="timeout 60s pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -p${test_pass} h=${test_host},P=${test_port}"
        osc_comm="${osc_comm},u=${test_user},D=${test_db},t=${_t_},A=utf8"
        osc_comm_tmp="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -pxxxxxx h=${test_host},P=${test_port}"
        osc_comm_tmp="${osc_comm_tmp},u=${test_user},D=${test_db},t=${_t_},A=utf8"
        [ "${slave_mark_sbm}x" != "604800x" ] && [ -n "${check_slave_repl_list}" ] && osc_array+=("${check_slave_repl_list}")  #如果是生产就判断延迟
    fi

    if [ "${#_t_}" -gt 58 ]
    then
        f_logging "$(eval echo ${log_addr}):ERROR" "本次改表使用'${_tools}'，但是目标表名[${_t_}]长度[${#_t_}其中有5个字符是基础长度]超过MySQL限长64个字符，本次改表失败" "2"
        return 1
    fi

    res_file="${res_log}.tmp"
    f_logging "$(eval echo ${log_addr}):COMMAND" "本次改表在测试环境执行的操作 ] [ ${osc_comm_tmp}" "execute:${execute}"
    if [ "${execute}x" == "0x" ]
    then
        __="$(f_exe_sql_in_test_mysql "show create table ${test_db}.${t_tmp}\G" "" "$(eval echo ${log_addr})")"
        echo "${__}" >> ${log_file}
    fi
    f_logging "$(eval echo ${log_addr}):REMAIND" "如下是改表前的表结构 ] [ ${__} ] [ ${line}" "execute:${execute}" >/dev/null
    f_logging "$(eval echo ${log_addr}):REMAIND" "开始在测试环境改表操作" "execute:${execute}"
    if [ "${execute}x" == "0x" ]
    then
        eval ${osc_comm} > ${res_log_test} 2>&1 && osc_exe_state="${?}" || osc_exe_state="${?}"
    else
        osc_exe_state=0
    fi

    if [ ${osc_exe_state} -eq 0 ] && [ "${execute}x" == "0x" ]
    then
        f_update_onlineddl_state_to_table_info "false" "预执行成功" "${_t_}"
        __="$(f_exe_sql_in_test_mysql "show create table ${test_db}.${t_tmp}\G" "" "$(eval echo ${log_addr})")"
        echo "${__}" >> ${log_file}
        f_logging "$(eval echo ${log_addr}):REMAIND" "如下是改表后的表结构 ] [ ${__}" "execute:${execute}" >/dev/null
        f_logging "$(eval echo ${log_addr}):INFO" "在测试环境 '${test_host}:${test_port}' 执行成功 ] [ ${line}" "execute:${execute}"
        f_check_table_after_ddl "${_t_}"
        if [ "${execute}x" != "1x" ]
        then
            {
                [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file}
                [ -f "${script_queue_file}" ] && rm -f "${script_queue_file}"
            } || true
            return 0
        fi
    elif [ ${osc_exe_state} -ne 0 ]
    then
        f_kill_osc_process "${_tools}" "${test_host}" "${test_port}" "${test_db}" "${_t_}" "${mysql_user}" || true
        if [ "${execute}x" != "1x" ]
        then
            {
                __="$(tail -100 ${res_log_test}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iw "ERROR"|grep -v "\[info\]"\
                    |grep -P "^\d{4}-\d{2}-\d{2}"|grep -v "ERROR Maximal timeout is 10sec. Timeout remains at 3"|awk '{
                    for(i=3;i<=NF;i++){if(i==NF){printf $i;}else{printf $i" ";}}printf"\n"}' |awk '{if ((!a[$0]++)==1){
                    printf "\n\t'${t_tmp}' ERROR"NR" : "$0}}'|sed 's/, $//g')"
                grep -q "FATAL No shared unique key can be found after ALTER! Bailing out" ${res_log_test} && echo 3 > ${bug_mark_file}
                grep -q "To force this operation to continue, supply --allow-nullable-unique-key flag." ${res_log_test} && echo 4 > ${bug_mark_file}
                [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file}
                [ -f "${script_queue_file}" ] && rm -f "${script_queue_file}"
            } || true

            if [ -f "${bug_mark_file}" ]
            then
                __="测试环境执行不通过, 遇到ghost的限制"
                if [ "$(cat ${bug_mark_file})x" == "3x" ]
                then
                    f_logging "$(eval echo ${log_addr}):ERROR" "${__}[FATAL No shared unique key can be found after ALTER!"
                    f_logging "$(eval echo ${log_addr}):ERROR" "如果是重建了主键, 建议先对新的主键字段(联合字段)新加个唯一索引, 然后再重建主键, 最后删掉新加的唯一索引. "
                    f_logging "$(eval echo ${log_addr}):ERROR" "例如：原来的主键是primary key(id,uid), 现在想将主键变成primary key(id);可以先提交一个工单执行'add unique key uniq_id(id);', 然后提交工单执行'drop primary key,add primary key(id);', 最后提交工单删除唯一索引'drop index uniqu_id;'"
                elif [ "$(cat ${bug_mark_file})x" == "4x" ]
                then
                    f_logging "$(eval echo ${log_addr}):ERROR" "${__}[To force this operation to continue, supply --allow-nullable-unique-key flag."
                fi
                [ "${format_mark}x" == "1x" ] && f_exit "1"
                f_update_onlineddl_state_to_table_info "false" "预执行失败, 失败原因可能是遇到gh-ost的使用限制, 请联系值班dba" "${_t_}"
                f_logging "$(eval echo ${log_addr}):ERROR" "现在使用pt再次改表"
                unset __ && return 100
            else
                declare grep_list
                grep_list="failed|--no-check-alter|--allow-nullable-unique|--alter-foreign-keys-method"
                [ -z "${__}" ] && __=$(tail -100 ${res_log_test}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iwE "${grep_list}"|awk '{
                    for(i=1;i<=NF;i++){if(i==NF){printf $i;}else{printf $i" ";}}printf"\n"}' |awk '{if ((!a[$0]++)==1){
                    printf "\n\t'${t_tmp}' ERROR"NR" : "$0}}'|sed 's/, $//g')
                exe_sql_get_error_info_list+=("${__}] [ ${line}")
                f_update_onlineddl_state_to_table_info "false" "预执行失败, 失败原因如下:${__}, 请联系值班dba" "${_t_}"
                return 0
            fi
        else
            f_update_onlineddl_state_to_table_info "false" "预执行失败, 遇到未知的失败, 请联系值班dba" "${_t_}"
            f_record_info_to_dbadb "${_tools}" "${_t_}" "测试遇到未知失败. 详情请看${localhost_ip}:${res_log_test}" || true
            { tail -10 ${res_log_test}|tee -a ${log_file};} || true
            f_logging "$(eval echo ${log_addr}):ERROR" "在测试环境 '${test_host}:${test_port}' 执行失败, 详情请看osc执行日志 '${res_log_test}' ] [ ${line}" "2" "1"
        fi
    fi

    f_logging "$(eval echo ${log_addr}):REMAIND" "现在开始在 '${mysql_host}:${mysql_port}' 环境执行提交的改表语句"

    if [ "${_tools}x" == "gh-ostx" ]
    then
        osc_comm="gh-ost --host=${mysql_host} --port=${mysql_port} --user=${mysql_user} --password=${mysql_pass} --database=${mysql_db}"
        osc_comm="${osc_comm} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        osc_comm_tmp="gh-ost --host=${mysql_host} --port=${mysql_port} --user=${mysql_user} --password=xxxxxx --database=${mysql_db}"
        osc_comm_tmp="${osc_comm_tmp} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
    else
        osc_comm="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -p${mysql_pass} h=${mysql_host},P=${mysql_port}"
        osc_comm="${osc_comm},u=${mysql_user},D=${mysql_db},t=${_t_},A=utf8"
        osc_comm_tmp="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -pxxxxxx h=${mysql_host},P=${mysql_port}"
        osc_comm_tmp="${osc_comm_tmp},u=${mysql_user},D=${mysql_db},t=${_t_},A=utf8"
    fi

    { f_check_mdl_lock_daemonize "${_tools}" "${_t_}" >> ${log_file} || true;} &

    { f_check_daemonize "${_tools}" "${_t_}" || true;} &

    f_logging "$(eval echo ${log_addr}):COMMAND" "本次改表在线上环境执行的操作 ] [ ${osc_comm_tmp}"
    f_check_tmp_table "${_tools}" "${_t_}"
    __="$(f_exe_sql_in_mysql "show create table ${_mysql_db_}.${t_tmp}\G" "" "" "" "$(eval echo ${log_addr})")"
    echo "${__}" >> ${log_file}
    f_logging "$(eval echo ${log_addr}):REMAIND" "如下是改表前的表结构 ] [ ${__} ] [ ${line}" >/dev/null
    f_logging "$(eval echo ${log_addr}):REMAIND" "开始在线上环境改表操作"
    [ -S "${gh_socket_file}" -o -f "${gh_socket_file}" ] && rm -f "${gh_socket_file}"
    eval ${osc_comm} > ${res_log} 2>&1 && osc_exe_state="${?}" || osc_exe_state="${?}"
    f_logging "$(eval echo ${log_addr}):REMAIND" "注 : 改表在线上环境执行结束, 但是不代表任务执行成功 ] [ ${line}"
    #改表任务结束, 删除标志文件, 这个文件删除以后检查mdl状态的任务基本就结束了(可能存在几秒延迟)
    { [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file};} || true

    f_logging "$(eval echo ${log_addr}):WARN" "正在等待mdl检查任务结束(最长120秒), 如果需要手动终止检查mdl任务可以删除'${check_mdl_mark_file}'文件"
    for (( wait_time=0; wait_time<120; wait_time++ ))
    do  #等待检查mdl任务完成, 最多等待120s
        sleep 1
        [ ! -f "${check_mdl_mark_file}" -a ! -f "${check_connect_file}" ] && break
    done
    
    { 
        [ -f "${check_mdl_mark_file}" ] && rm -f ${check_mdl_mark_file}
        [ -f "${check_connect_file}" ] && rm -f ${check_connect_file}
    } || true

    f_logging "$(eval echo ${log_addr}):INFO" "mdl检查任务完成"

    [ -f "${pause_file_name}" ] && osc_exe_state="-1"
    [ -f "${has_max_process_file}" ] && osc_exe_state="-2"

    if [ ${osc_exe_state} -ne 0 ] && [ ! -f "${has_mdl_lock_file}" ] && [ ! -f "${has_max_process_file}" ]
    then #清理临时表
        f_delete_tmp_table "${_tools}" "${mysql_db}" "${_t_}" "${mysql_host}" "原因是改表任务执行异常, 临时表未清理"
    fi

    if [ ${osc_exe_state} -eq 0 ]
    then
        __="$(f_exe_sql_in_mysql "show create table ${_mysql_db_}.${t_tmp}\G" "" "" "" "$(eval echo ${log_addr})")"
        echo "${__}" >> ${log_file}
        f_logging "$(eval echo ${log_addr}):REMAIND" "如下是改表后的表结构 ] [ ${__}" >/dev/null
        f_logging "$(eval echo ${log_addr}):INFO" "在 '${mysql_host}:${mysql_port}' 环境执行提交的改表语句, 执行成功 ] [ ${line}"
    elif [ "${osc_exe_state}x" == "-1x" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到mdl等待. 详情请看${localhost_ip}:${log_file}" "mail" "遇到mdl等待,改表终止 如有疑问请联系dba" || true
        f_logging "$(eval echo ${log_addr}):ERROR" "在线上环境 '${mysql_host}:${mysql_port}' 遇到mdl等待, 终止任务, 详情请看 '${log_file}' ] [ ${line}" "2" "1"
    elif [ "${osc_exe_state}x" == "-2x" ] && [ "$(cat ${has_max_process_file})x" == "threadx" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到活跃连接数过高. 详情请看${localhost_ip}:${log_file}" "mail" "活跃连接数过高,改表终止 如有疑问请联系dba" || true
        f_logging "$(eval echo ${log_addr}):ERROR" "在线上环境 '${mysql_host}:${mysql_port}' 遇到活跃连接数过高, 终止任务 ] [ ${line}" "2" "1"
    elif [ "${osc_exe_state}x" == "-2x" ] && [ "$(cat ${has_max_process_file})x" == "connectx" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到连接数过高. 详情请看${localhost_ip}:${log_file}" "mail" "连接数过高,改表终止 如有疑问请联系dba" || true
        f_logging "$(eval echo ${log_addr}):ERROR" "在线上环境 '${mysql_host}:${mysql_port}' 遇到连接数过高, 终止任务 ] [ ${line}" "2" "1"
    else
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到未知失败. 详情请看${localhost_ip}:${res_log}" || true
        tail -10 ${res_log}|grep -vP "^(Copy:)|(Terminated$)" || true
        __="$(tail -100 ${res_log}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iw "ERROR"|tail -1) ] [ 在 '${mysql_host}:${mysql_port}' " || true
        f_logging "$(eval echo ${log_addr}):ERROR" "${__}环境执行提交的改表语句, 执行失败, 详情请查看osc工具执行日志 '${res_log}' ] [ ${line}" "2"

        if [ "${_tools}x" != "gh-ostx" ] && [ "$(grep -c "^Successfully altered .${mysql_db}...${_t_}..$" ${res_log})x" == "1x" ]
        then #有时候执行完成但是返回状态码是非0
            f_logging "$(eval echo ${log_addr}):ERROR" "可能实际已经改成功了, 但是命令返回状态是非0, 请前往环境进行检查确认!!!" "2"
        fi
        if [ -f "${bug_mark_file}" ]
        then
            return 100
        else
            f_exit "1"
        fi
    fi

    if [ "${global_is_supp_add_uk}x" == "truex" ] && [ "${_tools}x" == "gh-ostx" ]
    then #唯一索引延迟删除临时表, pt不用执行这个
        f_logging "$(eval echo ${log_addr}):REMAIND" "本次改表任务是添加唯一索引, 所以临时表将延后两天删除" "2"
        cd ${work_dir} && bash main.sh -a later_drop_table -P ${mysql_port} -D ${mysql_db} -T "_${_t_}_del" -u ${g_user_mail_addr} -O $(date +%s)
    fi

    return 0
}
